﻿// (c) Copyright 2013 Mike Riedel.
// This source is subject to the Microsoft Public License (Ms-PL).
// All other rights reserved.

using System;
using System.Collections.Generic;

namespace FreshMeat.Storage
{
   /// <summary>
   /// Provides the ability to store, retrieve and delete items of type <typeparamref name="TItem"/>
   /// each with an identifier of type <typeparamref name="TId"/>.
   /// </summary>
   /// <remarks>
   /// <para>
   /// The goal is to provide a level of abstraction from the details involved in actually
   /// storing and retrieving the data. Concrete implementations will expose some of those
   /// detail, e.g. a file-based implementation would need to know where the files are
   /// located and a SQL-based implementation would need to know the connection string.
   /// By writing against this interface instead of a specific implementation, code can
   /// remain blissfully unaware of the details.
   /// </para>
   /// <para>
   /// An key aspect of all implementations is how items of type <typeparamref name="TItem"/> are converted
   /// to and from the storage format.  A file-based system converts to and from a stream of bytes 
   /// using serialization while SQL typically entails mapping the items to an intermediate type
   /// from which SQL commands are generated.
   /// </para>
   /// </remarks>
   /// <typeparam name="TId">Type of ID.</typeparam>
   /// <typeparam name="TItem">Type of item.</typeparam>
   public interface IRepository<TId, TItem>
   {
      /// <summary>
      /// Saves an item.
      /// If an item with the same ID already exists, it is ovewritten; otherwise, the item is created.
      /// The item is not modified in any way.
      /// The caller is free to modify the item after saving; doing so will not affect the saved item.
      /// </summary>
      /// <param name="item"></param>
      /// <returns>True if the item already existed, false if it was created.</returns>
      bool Save(TItem item);

      /// <summary>
      /// Saves zero or more items.
      /// Everything written in <see cref="Save(TItem)"/> applies to each item here.
      /// For multiple items this is faster (and more convenient) than saving items one at a time.
      /// </summary>
      /// <param name="items">Items to save.</param>
      /// <returns>The number of items that already existed or 0 if all items were just created.
      /// Note that if <paramref name="items"/> is empty then this value will also be 0.</returns>
      int Save(IEnumerable<TItem> items);

      /// <summary>
      /// Attempts to load an item.
      /// </summary>
      /// <param name="id">The item's ID.</param>
      /// <param name="factory">Optional function to supply a value to be returned if the item doesn't 
      /// exist; if this is null then <see cref="NotFoundException"/> is thrown if the item doesn't exist.</param>
      /// <returns>The item that was loaded or the value returned by the factory function.</returns>
      TItem Load(TId id, Func<TId, TItem> factory = null);

      /// <summary>
      /// Attempts to load zero or more items.
      /// Everything written in <see cref="Load(TId,Func{TId,TItem})"/> applies to each item here.
      /// For multiple items this is faster (and more convenient) than loading items one at a time.
      /// </summary>
      /// <param name="ids">ID's of items to load.</param>
      /// <param name="factory">Optional function to supply a value to be returned if the item doesn't 
      /// exist; if this is null then <see cref="NotFoundException"/> is thrown if the item doesn't exist.</param>
      /// <returns>Items that were loaded and/or the values returned by the factory function.</returns>
      IEnumerable<TItem> Load(IEnumerable<TId> ids, Func<TId, TItem> factory = null);

      /// <summary>
      /// Loads all items.
      /// </summary>
      /// <returns>Items that were loaded; this may be empty if no items exist.</returns>
      IEnumerable<TItem> Load();

      /// <summary>
      /// Attempts to delete an item.
      /// </summary>
      /// <param name="id">The item's ID.</param>
      /// <returns>True if the item was deleted; false if it did not exist.</returns>
      bool Delete(TId id);

      /// <summary>
      /// Attempts to delete zero or more items.
      /// </summary>
      /// <param name="ids">ID's of items to delete.</param>
      /// <returns>The number of items that were deleted.</returns>
      int Delete(IEnumerable<TId> ids);
   }
}